//
//  HalfModalPresentationController.swift
//  HalfModalPresentationController
//
//  Created by Martin Normark on 17/01/16.
//  Copyright © 2016 martinnormark. All rights reserved.
//

import UIKit

public enum ModalScaleState {
    case adjustedOnce
    case normal
}

public class HalfModalPresentationController: UIPresentationController {
    var isMaximized: Bool = false
    
    var panGestureRecognizer: UIPanGestureRecognizer
    var direction: CGFloat = 0
    var specialHeight: CGFloat? = 528
    var keyBoardHeight: CGFloat = 0
    var addBlurEffect: Bool = false
    var state: ModalScaleState = .normal
    
    public var touchDimmingViewHidden: Bool = true
    
    lazy var dimmingView: UIView? = {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: containerView!.bounds.width, height: containerView!.bounds.height))
        
        if addBlurEffect {
            // Blur Effect
            let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.light)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            blurEffectView.frame = view.bounds
            view.addSubview(blurEffectView)
            
            // Vibrancy Effect
            let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
            let vibrancyEffectView = UIVisualEffectView(effect: vibrancyEffect)
            vibrancyEffectView.frame = view.bounds
            
            // Add the vibrancy view to the blur view
            blurEffectView.contentView.addSubview(vibrancyEffectView)
        } else {
            view.backgroundColor = UIColor.black.withAlphaComponent(0.4)
        }
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(dimmingViewOnPan(pan:)))
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
        
        return view
    }()
    
    override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
        self.panGestureRecognizer = UIPanGestureRecognizer()
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        panGestureRecognizer.addTarget(self, action: #selector(onPan(pan:)))
        presentedViewController.view.addGestureRecognizer(panGestureRecognizer)
       
    }
    
    @objc func dimmingViewOnPan(pan: UIPanGestureRecognizer) {
        if touchDimmingViewHidden {
            presentedViewController.dismiss(animated: true, completion: nil)
        }
    }
    
    private var originY: CGFloat = 0
    
    @objc func onPan(pan: UIPanGestureRecognizer) {
        let endPoint = pan.translation(in: pan.view?.superview)
        
        _ = specialHeight ?? (containerView!.frame.height / 2)
        switch pan.state {
        case .began:
            originY = presentedView!.frame.origin.y
//            presentedView!.frame.size.height = containerView!.frame.height - keyBoardHeight
//            presentedView!.frame.origin.y = endPoint.y + height - keyBoardHeight
            break
        case .changed:
            let velocity = pan.velocity(in: pan.view?.superview)
//            print(velocity.y)
            print(endPoint.y)
            switch state {
            case .normal:
                let newY = originY + endPoint.y
                presentedView!.frame.origin.y = newY > originY ? newY : originY //+ height - keyBoardHeight
            case .adjustedOnce:
                presentedView!.frame.origin.y = endPoint.y - keyBoardHeight
            }
            direction = velocity.y
            
        case .ended:
            if direction < 0 {
                changeScale(to: .normal, keyBoardHeight)
            } else {
                if state == .adjustedOnce {
                    changeScale(to: .normal, keyBoardHeight)
                } else {
                    presentedViewController.dismiss(animated: true, completion: nil)
                }
            }
            
            print("finished transition")
            
        default:
            break
        }
    }
    
    public func changeScale(to state: ModalScaleState, _ keyboard: CGFloat = 0) {
        keyBoardHeight = keyboard
        if keyboard != 0 {
            presentedViewController.view.removeGestureRecognizer(panGestureRecognizer)
        }
        
        if let presentedView = presentedView, let containerView = self.containerView {
            UIView.animate(withDuration: 0.6, delay: 0, options: .curveEaseInOut,
                           animations: { () -> Void in
                               presentedView.frame = containerView.frame
                               let containerFrame = containerView.frame
                               
                               let height = self.specialHeight ?? (containerFrame.height / 2)
                               
                               let origin = CGPoint(x: 0, y: containerFrame.height - height - keyboard)
                               let halfFrame = CGRect(origin: origin,
                                                      size: CGSize(width: containerFrame.width, height: height))
                               let frame = state == .adjustedOnce ? containerView.frame : halfFrame
                               
                               presentedView.frame = frame
                               
                               if let navController = self.presentedViewController as? UINavigationController {
                                   self.isMaximized = true
                                   
                                   navController.setNeedsStatusBarAppearanceUpdate()
                                   
                                   // Force the navigation bar to update its size
                                   navController.isNavigationBarHidden = true
                                   navController.isNavigationBarHidden = false
                               }
                           }, completion: { _ in
                               self.state = state
                               if keyboard == 0 {
                                   self.presentedViewController.view.addGestureRecognizer(self.panGestureRecognizer)
                               }
            })
        }
    }
    
    public override var frameOfPresentedViewInContainerView: CGRect {
        let truelyH = (specialHeight ?? containerView!.bounds.height / 2)
        return CGRect(x: 0, y: containerView!.bounds.height - truelyH, width: containerView!.bounds.width, height: truelyH)
    }
    
    public override func presentationTransitionWillBegin() {
        let dimmedView = dimmingView
        
        if let containerView = self.containerView, let coordinator = presentingViewController.transitionCoordinator {
            if let dimmedView = dimmedView {
                dimmedView.alpha = 0
                containerView.addSubview(dimmedView)
                dimmedView.addSubview(presentedViewController.view)
            }
            
            coordinator.animate(alongsideTransition: { (_) -> Void in
                dimmedView?.alpha = 1
//                self.presentingViewController.view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
            }, completion: nil)
        }
    }
    
    public override func dismissalTransitionWillBegin() {
        if let coordinator = presentingViewController.transitionCoordinator {
            coordinator.animate(alongsideTransition: { (_) -> Void in
                self.dimmingView?.alpha = 0
                self.presentingViewController.view.transform = CGAffineTransform.identity
            }, completion: { (_) -> Void in
                print("done dismiss animation")
            })
        }
    }
    
    public override func dismissalTransitionDidEnd(_ completed: Bool) {
        print("dismissal did end: \(completed)")
        
        if completed, let dimmingView = dimmingView {
            dimmingView.removeFromSuperview()
            self.dimmingView = nil
            
            isMaximized = false
        }
    }
}

public protocol HalfModalPresentable {}

public extension HalfModalPresentable where Self: UIViewController {
    func maximizeToFullScreen() {
        if let presetation = navigationController?.presentationController as? HalfModalPresentationController {
            presetation.changeScale(to: .adjustedOnce)
        }
    }
    
    func updateForKeyBoard(_ height: CGFloat) {
        if let presetation = navigationController?.presentationController as? HalfModalPresentationController {
            presetation.changeScale(to: .normal, height)
        }
    }
}

public extension HalfModalPresentable where Self: UINavigationController {
    func isHalfModalMaximized() -> Bool {
        if let presentationController = presentationController as? HalfModalPresentationController {
            return presentationController.isMaximized
        }
        
        return false
    }
}
